package com.todo.admin.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import com.todo.admin.common.base.consts.Constants.UploadSubDir;
import com.todo.admin.common.base.dto.ResponseDTO;
import com.todo.admin.common.exception.ApiException;
import com.todo.admin.common.exception.error.ErrorCode;
import com.todo.admin.common.exception.error.ErrorCode.Business;
import com.todo.admin.entity.dto.UploadDTO;
import com.todo.admin.service.FileService;
import com.todo.admin.util.file.FileUploadUtils;
import com.todo.common.common.entity.response.BizResponse;
import com.todo.common.common.enums.BusinessSceneEnum;
import com.todo.common.utils.ServletHolderUtil;
import com.todo.common.utils.jackson.JacksonUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * 通用请求处理
 * TODO
 *
 * @author azhebuxing
 */
@Tag(name = "上传API", description = "上传相关接口")
@RestController
@RequestMapping("/file")
@Slf4j
public class FileController {

    @Resource
    private FileService fileService;

    @PostMapping("upload")
    @Operation(summary = "文件上传")
    public BizResponse<String> upload(MultipartFile file) {
        if (file.isEmpty()) {
            return BizResponse.operationFailed("file is empty");
        }
        return BizResponse.success(fileService.upload(file));
    }

    @PostMapping("multipartUpload")
    @Operation(summary = "多文件上传")
    public BizResponse<List<String>> multipartUpload(List<MultipartFile> fileList) {
        if (CollectionUtils.isEmpty(fileList)) {
            return BizResponse.operationFailed("file is empty");
        }
        return BizResponse.success(fileService.multipartUpload((fileList)));
    }


    @PostMapping("uploadSight")
    @Operation(summary = "文件上传-景点")
    public BizResponse<String> uploadSight(MultipartFile file) {
        if (file.isEmpty()) {
            return BizResponse.operationFailed("file is empty");
        }
        return BizResponse.success(fileService.upload(file, BusinessSceneEnum.SIGHT.getSceneCode()));
    }

    @PostMapping("multipartUploadSight")
    @Operation(summary = "多文件上传-景点")
    public BizResponse<List<String>> multipartUploadSight(List<MultipartFile> fileList) {
        if (CollectionUtils.isEmpty(fileList)) {
            return BizResponse.operationFailed("file is empty");
        }
        return BizResponse.success(fileService.multipartUpload((fileList), BusinessSceneEnum.SIGHT.getSceneCode()));
    }

    @PostMapping("uploadStrategy")
    @Operation(summary = "文件上传-景点")
    public BizResponse<String> uploadStrategy(MultipartFile file) {
        if (file.isEmpty()) {
            return BizResponse.operationFailed("file is empty");
        }
        return BizResponse.success(fileService.upload(file, BusinessSceneEnum.STRATEGY.getSceneCode()));
    }

    @PostMapping("multipartUploadStrategy")
    @Operation(summary = "多文件上传-景点")
    public BizResponse<List<String>> multipartUploadStrategy(List<MultipartFile> fileList) {
        if (CollectionUtils.isEmpty(fileList)) {
            return BizResponse.operationFailed("file is empty");
        }
        return BizResponse.success(fileService.multipartUpload((fileList), BusinessSceneEnum.STRATEGY.getSceneCode()));
    }

    /**
     * 通用下载请求
     * download接口  其实不是很有必要
     *
     * @param fileName 文件名称
     */
    @Deprecated
    @Operation(summary = "本地下载文件")
    @GetMapping("/fileDownload")
    public ResponseEntity<byte[]> fileDownload(String fileName, HttpServletResponse response) {
        try {
            if (!FileUploadUtils.isAllowDownload(fileName)) {
                // 返回类型是ResponseEntity 不能捕获异常， 需要手动将错误填到 ResponseEntity
                ResponseDTO<Object> fail = ResponseDTO.fail(
                        new ApiException(Business.COMMON_FILE_NOT_ALLOWED_TO_DOWNLOAD, fileName));
                return new ResponseEntity<>(JacksonUtil.to(fail).getBytes(), null, HttpStatus.OK);
            }

            String filePath = FileUploadUtils.getFileAbsolutePath(UploadSubDir.DOWNLOAD_PATH, fileName);

            HttpHeaders downloadHeader = FileUploadUtils.getDownloadHeader(fileName);

            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            return new ResponseEntity<>(FileUtil.readBytes(filePath), downloadHeader, HttpStatus.OK);
        } catch (Exception e) {
            log.error("下载文件失败", e);
            return null;
        }
    }

    /**
     * 通用上传请求（单个）
     */
    @Deprecated
    @Operation(summary = "本地单个上传文件")
    @PostMapping("/localUploadFile")
    public ResponseDTO<UploadDTO> loaclUploadFile(MultipartFile file) {
        if (file == null) {
            throw new ApiException(ErrorCode.Business.UPLOAD_FILE_IS_EMPTY);
        }

        // 上传并返回新文件名称
        String fileName = FileUploadUtils.upload(UploadSubDir.UPLOAD_PATH, file);

        String url = ServletHolderUtil.getContextUrl() + fileName;

        UploadDTO uploadDTO = UploadDTO.builder()
                // 全路径
                .url(url)
                // 相对路径
                .fileName(fileName)
                // 新生成的文件名
                .newFileName(FileNameUtil.getName(fileName))
                // 原始的文件名
                .originalFilename(file.getOriginalFilename()).build();

        return ResponseDTO.ok(uploadDTO);
    }

    /**
     * 通用上传请求（多个）
     */
    @Deprecated
    @Operation(summary = "本地多个上传文件")
    @PostMapping("/localUploadFiles")
    public ResponseDTO<List<UploadDTO>> localUploadFiles(List<MultipartFile> files) {
        if (CollUtil.isEmpty(files)) {
            throw new ApiException(ErrorCode.Business.UPLOAD_FILE_IS_EMPTY);
        }

        List<UploadDTO> uploads = new ArrayList<>();

        for (MultipartFile file : files) {
            if (file != null) {
                // 上传并返回新文件名称
                String fileName = FileUploadUtils.upload(UploadSubDir.UPLOAD_PATH, file);
                String url = ServletHolderUtil.getContextUrl() + fileName;
                UploadDTO uploadDTO = UploadDTO.builder()
                        .url(url)
                        .fileName(fileName)
                        .newFileName(FileNameUtil.getName(fileName))
                        .originalFilename(file.getOriginalFilename()).build();

                uploads.add(uploadDTO);

            }
        }
        return ResponseDTO.ok(uploads);
    }

}
